﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;



class ControlMethod
{
    public ControlMethod(BaseController ctrl = null)
    {
        var actions = ctrl.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)
                          .Where(_ => _.GetCustomAttributes(typeof(AcitonAttribute), true).Length > 0);

        foreach (var item in actions)
        {
            var action = item.GetCustomAttribute<AcitonAttribute>();

            if (string.IsNullOrEmpty(action.Cmd))
            { 
                action.Cmd = item.Name;
            }

            if (item.ReturnType == typeof(void))
            {
                actionDics.Add(action.Cmd, (msg) => item.Invoke(ctrl, msg.args));
            }
            else
            {
                funcDics.Add(action.Cmd,   (msg) => item.Invoke(ctrl, msg.args));
            }
        }

        var fields = ctrl.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)
                          .Where(_ => _.GetCustomAttributes(typeof(ArgAttribute), true).Length > 0);

        foreach (var item in fields)
        {
            var action = item.GetCustomAttribute<ArgAttribute>();
            
            if (string.IsNullOrEmpty(action.Cmd))
            {
                action.Cmd = item.Name;
            }

            argDics.Add(action.Cmd, () => item.GetValue(ctrl));
        }

     
        CallSystem.AddListener(Invoke);
        CallSystem.AddFuncListener(ArgInvoke);
        CallSystem.AddMethodListener(MethodInvoke);
    }

    public Dictionary<string, System.Action<CtrlMsg>> actionDics   = new Dictionary<string, System.Action<CtrlMsg>>();
    public Dictionary<string, CallSystem.FuncNotDelegate> argDics  = new Dictionary<string, CallSystem.FuncNotDelegate>();
    public Dictionary<string, CallSystem.FuncMsgDelegate> funcDics = new Dictionary<string, CallSystem.FuncMsgDelegate>();
    public void Clear()
    {
        argDics    . Clear();
        funcDics   . Clear();
        actionDics . Clear();
        CallSystem . RemoveListener(Invoke);
        CallSystem . RemoveFuncListener(ArgInvoke);
        CallSystem . RemoveMethodListener(MethodInvoke);
    }

    public void Invoke(CtrlMsg msg)
    {
        if (actionDics.TryGetValue(msg.cmd, out System.Action<CtrlMsg> action))
        {
            action?.Invoke(msg);
        }
    }

    public bool ArgInvoke(string fieldID ,ref object resulf)
    {
        if (argDics.TryGetValue(fieldID, out CallSystem.FuncNotDelegate action))
        {
            resulf = action();
            return true;
        }
        return false;
    }

    public bool MethodInvoke(CtrlMsg msg ,ref object resulf)
    {
        if (funcDics.TryGetValue(msg.cmd, out CallSystem.FuncMsgDelegate action))
        {
            resulf = action(msg);
            return true;
        }
        return false;
    }
}




public abstract class BaseController : MonoBehaviour
{
    private ControlMethod _method;

    /// <summary>
    /// 查找子类中所有带ActionMethod特性的函数
    /// </summary>
    private void InitActionMethos()
    {
        if (_method == null)
            _method = new ControlMethod(this);
    }

    private void ClearActionMethos()
    {
        _method?.Clear();
    }

    void Awake()
    {
        InitActionMethos();
        OnAwake();
    }

    void OnDestroy()
    {
        ClearActionMethos();
        OnDelete();
    }


    public virtual void OnAwake()
    {
       
    }

    public virtual void OnDelete()
    {
      
    }
}


/// <summary>
/// MVC 结构中的 控制逻辑模块
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class Controller : BaseController 
{
    protected View _view;
    protected Data _data;

    public U SwicthData<U>() where U : Data
    { 
        return (U)(_data ?? GetSelfComponent<Data>());
    }

    public U SwicthView<U>() where U : View
    {
        return (U)(_view ?? GetSelfComponent<View>());
    }

    protected T GetSelfComponent<T>()
    {
        return transform.GetComponent<T>() ?? transform.GetComponentInChildren<T>(true);
    }

}
